home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / groff108.lha / groff-1.08 / groff / pipeline.c < prev    next >
C/C++ Source or Header  |  1992-08-08  |  5KB  |  241 lines

  1. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  2.      Written by James Clark (jjc@jclark.com)
  3.  
  4. This file is part of groff.
  5.  
  6. groff is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 2, or (at your option) any later
  9. version.
  10.  
  11. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  12. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14. for more details.
  15.  
  16. You should have received a copy of the GNU General Public License along
  17. with groff; see the file COPYING.  If not, write to the Free Software
  18. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  19.  
  20. /*
  21. Compile options are:
  22.  
  23. -DWCOREFLAG=0200 (or whatever)
  24. -DHAVE_VFORK_H
  25. -Dvfork=fork
  26. -DHAVE_SYS_SIGLIST
  27. -DHAVE_UNISTD_H
  28. */
  29.  
  30. #include <stdio.h>
  31. #include <signal.h>
  32. #include <errno.h>
  33. #include <sys/types.h>
  34. #ifdef HAVE_UNISTD_H
  35. #include <unistd.h>
  36. #endif
  37. #ifdef HAVE_VFORK_H
  38. #include <vfork.h>
  39. #endif
  40.  
  41. #ifndef errno
  42. extern int errno;
  43. #endif
  44.  
  45. extern char *strerror();
  46.  
  47. #ifdef _POSIX_VERSION
  48.  
  49. #include <sys/wait.h>
  50.  
  51. #define PID_T pid_t
  52.  
  53. #else /* not _POSIX_VERSION */
  54.  
  55. /* traditional Unix */
  56.  
  57. #define WIFEXITED(s) (((s) & 0377) == 0)
  58. #define WIFSTOPPED(s) (((s) & 0377) == 0177)
  59. #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
  60. #define WEXITSTATUS(s) (((s) >> 8) & 0377)
  61. #define WTERMSIG(s) ((s) & 0177)
  62. #define WSTOPSIG(s) (((s) >> 8) & 0377)
  63.  
  64. #ifndef WCOREFLAG
  65. #define WCOREFLAG 0200
  66. #endif
  67.  
  68. #define PID_T int
  69.  
  70. #endif /* not _POSIX_VERSION */
  71.  
  72. /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
  73. #ifndef WCOREFLAG
  74. #ifdef WCOREFLG
  75. #define WCOREFLAG WCOREFLG
  76. #endif /* WCOREFLG */
  77. #endif /* not WCOREFLAG */
  78.  
  79. #ifndef WCOREDUMP
  80. #ifdef WCOREFLAG
  81. #define WCOREDUMP(s) ((s) & WCOREFLAG)
  82. #else /* not WCOREFLAG */
  83. #define WCOREDUMP(s) (0)
  84. #endif /* WCOREFLAG */
  85. #endif /* not WCOREDUMP */
  86.  
  87. #include "pipeline.h"
  88.  
  89. #ifdef __STDC__
  90. #define P(parms) parms
  91. #else
  92. #define P(parms) ()
  93. #endif
  94.  
  95. #define error c_error
  96. extern void error P((char *, char *, char *, char *));
  97.  
  98. static void sys_fatal P((char *));
  99. static char *strsignal P((int));
  100. static char *itoa P((int));
  101.  
  102. int run_pipeline(ncommands, commands)
  103.      int ncommands;
  104.      char ***commands;
  105. {
  106.   int i;
  107.   int last_input = 0;
  108.   PID_T pids[MAX_COMMANDS];
  109.   int ret = 0;
  110.   int proc_count = ncommands;
  111.  
  112.   for (i = 0; i < ncommands; i++) {
  113.       int pdes[2];
  114.       PID_T pid;
  115.       if (i != ncommands - 1) {
  116.     if (pipe(pdes) < 0)
  117.       sys_fatal("pipe");
  118.       }
  119.       pid = vfork();
  120.       if (pid < 0)
  121.     sys_fatal("fork");
  122.       if (pid == 0) {
  123.     /* child */
  124.     if (last_input != 0) {
  125.       if (close(0) < 0)
  126.         sys_fatal("close");
  127.       if (dup(last_input) < 0)
  128.         sys_fatal("dup");
  129.       if (close(last_input) < 0)
  130.         sys_fatal("close");
  131.     }
  132.     if (i != ncommands - 1) {
  133.       if (close(1) < 0)
  134.         sys_fatal("close");
  135.       if (dup(pdes[1]) < 0)
  136.         sys_fatal("dup");
  137.       if (close(pdes[1]) < 0)
  138.         sys_fatal("close");
  139.       if (close(pdes[0]))
  140.         sys_fatal("close");
  141.     }
  142.     execvp(commands[i][0], commands[i]);
  143.     error("couldn't exec %1: %2", commands[i][0],
  144.           strerror(errno), (char *)0);
  145.     fflush(stderr);        /* just in case error() doesn't */
  146.     _exit(EXEC_FAILED_EXIT_STATUS);
  147.       }
  148.       /* in the parent */
  149.       if (last_input != 0) {
  150.     if (close(last_input) < 0)
  151.       sys_fatal("close");
  152.       }
  153.       if (i != ncommands - 1) {
  154.     if (close(pdes[1]) < 0)
  155.       sys_fatal("close");
  156.     last_input = pdes[0];
  157.       }
  158.       pids[i] = pid;
  159.     }
  160.   while (proc_count > 0) {
  161.     int status;
  162.     PID_T pid = wait(&status);
  163.     if (pid < 0)
  164.       sys_fatal("wait");
  165.     for (i = 0; i < ncommands; i++)
  166.       if (pids[i] == pid) {
  167.     pids[i] = -1;
  168.     --proc_count;
  169.     if (WIFSIGNALED(status)) {
  170.       int sig = WTERMSIG(status);
  171. #ifdef SIGPIPE
  172.       if (sig == SIGPIPE) {
  173.         if (i == ncommands - 1) {
  174.  
  175.           /* This works around a problem that occurred when using the
  176.          rerasterize action in gxditview.  What seemed to be
  177.          happening (on SunOS 4.1.1) was that pclose() closed the
  178.          pipe and waited for groff, gtroff got a SIGPIPE, but
  179.          gpic blocked writing to gtroff, and so groff blocked
  180.          waiting for gpic and gxditview blocked waiting for
  181.          groff.  I don't understand why gpic wasn't getting a
  182.          SIGPIPE. */
  183.           int j;
  184.           for (j = 0; j < ncommands; j++)
  185.         if (pids[j] > 0)
  186.           (void)kill(pids[j], SIGPIPE);
  187.         }
  188.       }
  189.       else
  190. #endif /* SIGPIPE */
  191.       {
  192.         error("%1: %2%3",
  193.           commands[i][0],
  194.           strsignal(sig),
  195.           WCOREDUMP(status) ? " (core dumped)" : "");
  196.         ret |= 2;
  197.       }
  198.     }
  199.     else if (WIFEXITED(status)) {
  200.       int exit_status = WEXITSTATUS(status);
  201.       if (exit_status == EXEC_FAILED_EXIT_STATUS)
  202.         ret |= 4;
  203.       else if (exit_status != 0)
  204.         ret |= 1;
  205.     }
  206.     else
  207.       error("unexpected status %1",
  208.         itoa(status), (char *)0, (char *)0);
  209.     break;
  210.       }
  211.   }
  212.   return ret;
  213. }
  214.  
  215. static void sys_fatal(s)
  216.      char *s;
  217. {
  218.   c_fatal("%1: %2", s, strerror(errno), (char *)0);
  219. }
  220.  
  221. static char *itoa(n)
  222.      int n;
  223. {
  224.   static char buf[12];
  225.   sprintf(buf, "%d", n);
  226.   return buf;
  227. }
  228.  
  229. static char *strsignal(n)
  230.      int n;
  231. {
  232.   static char buf[sizeof("Signal ") + 1 + sizeof(int)*3];
  233. #ifdef HAVE_SYS_SIGLIST
  234.   extern char *sys_siglist[];
  235.   if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
  236.     return sys_siglist[n];
  237. #endif /* HAVE_SYS_SIGLIST */
  238.   sprintf(buf, "Signal %d", n);
  239.   return buf;
  240. }
  241.